home *** CD-ROM | disk | FTP | other *** search
/ AI Game Programming Wisdom / AIGameProgrammingWisdom.iso / SourceCode / 04 Pathfinding and Movement / 05 Hancock / Goal_RideElevator.cpp < prev    next >
Encoding:
Text File  |  2001-08-19  |  4.1 KB  |  131 lines

  1.  
  2.  
  3. Goal_RideElevator::Goal_RideElevator(AI* pAI, const PathLink *entryLink_, const PathNode *endNode) :
  4.     Goal( pAI ), GoalQueue(), entryLink(entryLink_), end(endNode), active(false)
  5. {
  6.     elevator = end->GetElevator();
  7.     if (!elevator){
  8.         mGoalStatus = statusFailed;
  9.         return;
  10.     }
  11.     //if entryLink is NULL, then we're inside the elevator to begin with
  12.     //otherwise entryLink is the link that leads us inside the elevator
  13.     if (entryLink)
  14.         stage = CallingElevator;
  15.     else {
  16.         stage = RidingElevator;
  17.     }
  18. }
  19.  
  20. Goal_RideElevator::~Goal_RideElevator()
  21. {
  22. }
  23.  
  24. bool Goal_RideElevator::ReplanSubgoals(){
  25.  
  26.     //while we're not inside the elevator and the elevator isn't moving to our floor or we're blocked by the elevator door, then replanning
  27.     //consists of calling the elevator via switch
  28.     switch (stage){
  29.     case CallingElevator:
  30.         {
  31.             const PathNode *bestswitchnode = NULL;
  32.             const Switch *bestswitch = NULL;
  33.  
  34.             int startFloor = entryLink->End()->elevatorFloor;
  35.  
  36.             //find the elevator switch that is reachable without going through a door or elevator
  37.             for (int i=0; i < elevator->NumControllers(); i++){
  38.                 CEntitySwitch *pSwitch = elevator->GetController(i);
  39.                 if (pSwitch->GetElevatorCallFloor() == startFloor){
  40.                     const PathNode *sn = g_NodeMap.GetSwitchLocation(pSwitch);
  41.                     if (sn && sn->NoDoorsBetween(entryLink->Start()) && sn->NoElevatorsBetween(entryLink->Start())){
  42.                         bestswitchnode = sn;
  43.                         bestswitch = pSwitch;
  44.                     }
  45.                 }
  46.             }
  47.             //if there isn't a call switch, we're going to assume that the elevator is region-triggered
  48.             //to be there when we get close
  49.             if (bestswitchnode){
  50.                 NewSubgoal(new Goal_HitElevatorCallSwitch(mpAI, bestswitchnode, elevator));
  51.             }
  52.             //move to the node in front of the elevator
  53.             NewSubgoal(new Goal_GotoNode(mpAI, entryLink->Start()));
  54.         }
  55.         return true;
  56.     case EnteringElevator:
  57.         {
  58.             //else if we're not inside the elevator, but it is at our floor and we're not blocked by the door
  59.             //then we need to get to the node in front of us and then enter the elevator
  60.             NewSubgoal(new Goal_GotoNode(mpAI, entryLink->Start()));
  61.             NewSubgoal(new Goal_FollowLink(mpAI, entryLink));
  62.         }
  63.         return true;
  64.     case RidingElevator:
  65.         {
  66.             const PathNode *bestswitchnode = NULL;
  67.  
  68.             //send a message to the elevator
  69.             Message_Int2* pMsg = new Message_Int2;
  70.             pMsg->GetData().id = Msg_ElevatorMoveToFloor;
  71.             pMsg->GetData().i1 = mpAI->Character()->ID();
  72.             pMsg->GetData().i2 = end->elevatorFloor;
  73.             gpSystem->Server()->SendMessageToObject( elevator->ID(), pMsg );
  74.  
  75.         }
  76.         return true;
  77.     default:
  78.         return false;
  79.     }
  80.     return true;
  81. }
  82.  
  83. // Update the goal
  84. void Goal_RideElevator::Update( float secs_elapsed )
  85. {
  86.     if (GoalStatus()!=statusInProgress) return;
  87.  
  88.     //if we haven't been activated yet, then we need to plan (replan) our subgoals
  89.     if (!active){
  90.         ReplanSubgoals();
  91.         active = true;
  92.         return;
  93.     }
  94.     
  95.    typeGoalStatus status = UpdateSubgoals( secs_elapsed ); //update the subgoals
  96.     if (status==statusFailed) {
  97.         mGoalStatus = statusFailed;
  98.         return; 
  99.     }
  100.  
  101.     if (!NoSubgoals()) return; //if we still have some subgoals, don't do anything else
  102.  
  103.     if (stage == RidingElevator){
  104.         if (elevator->FinishedMoving()){
  105.             if (elevator->GetDestinationFloor() == end->elevatorFloor)
  106.                 mGoalStatus = statusSucceeded; //we're done once the elevator has arrived at our floor
  107.             else
  108.                 ReplanSubgoals(); //this will send the elevator to go to the destination floor
  109.         }
  110.         else
  111.             mpAI->Stop(); //don't move until the elevator reaches the destination
  112.         return;
  113.     }
  114.     else if (stage == CallingElevator){
  115.         int startFloor = entryLink->End()->elevatorFloor;
  116.         //if the elevator's going to the wrong floor, we failed, so replan
  117.         if (startFloor != elevator->GetDestinationFloor()){
  118.             ReplanSubgoals();
  119.             return;
  120.         }
  121.         //wait for the elevator to arrive at our floor
  122.         if (!elevator->FinishedMoving()){
  123.             mpAI->Stop();
  124.             mpAI->TurnTo(entryLink->End()->pos);
  125.             return;
  126.         }
  127.     }
  128.     stage++; //we presumably finished the last stage since we have no subgoals, so increment the stage
  129.     ReplanSubgoals(); //plan the next stage of the elevator use
  130. }
  131.